import QtQuick 2.0
import VPlay 2.0
import "entities"
import "scripts/levelLogic.js" as LevelLogic

// the level gets moved in the negative y direction (so upwards) -> this has the effect that all entities in it are moving downwards!
// no Flickable is needed as root item, because it shouldnt be able to get pinched or moved by the user - instead the level gets moved downwards over time with increasing speed
//Flickable {
Item {
  id: level
  // use the logical size as the level size
  width: scene.width

  // just as an abbreviation of typing, so instead of scene.gridSize just gridSize can be written in this file
  property real gridSize: scene.gridSize

  // available columns for creating platforms - the current logical scene width is 320, gridSize is 48, so 6 and a half platforms can be displayed horizontally
  property int platformColumns: width/gridSize

  // gets used to measure how much the level was moved downwards in the last frame - if this is bigger than gridSize, a new row will be created in onYChanged
  property real lastY: 0

  // how many new rows were created, it starts with 0 if the level has y position 0, and then gets increased with every gridSize
  // gets initialized in onCompleted
  property real currentRow: 0

  // this is needed so an alias can be created from the main window!
  property alias player: player

  // specifies the px/second how much the level moves
  property real levelMovementSpeedMinimum: 30
  property real levelMovementSpeedMaximum: 100
  property real levelMovementAcceleration: 0.7
  // after 40seconds, the maximum speed will be reached
  property int levelMovementDurationTillMaximum: 20
  // makes sure that the old speed is not overwritten if a slowdowner is hit while a slowdowner is active
  property bool slowDownActive: false
  // same for speed-up
  property bool speedUpActive: false
  // if a slowdowner is activated, the old speed is stored to restore it when the time is triggered
  property real levelOldSpeedSpeedUp: 0.0
  property real levelOldSpeedSlowDowner: 0.0

  property real probabilityPlatform2: 0.6
  property real probabilityPlatform3: 0.4
  property real probabilityCoin: 0.1
  property real probabilityBooster: 0.2
  property real probabilitySlowDowner: 0.05

  EditableComponent {
      editableType: "Balancing"
      properties : {
          "levelMovementSpeedMinimum": {"min": 10, "max": 40, "label": "levelMovementSpeedMinimum"},
          "levelMovementSpeedMaximum": {"min": 80, "max": 500, "label": "levelMovementSpeedMaximum"},
          "levelMovementAcceleration": {"min": 0.0, "max": 1.0, "label": "levelMovementAcceleration"},

//  Note: if these values are made available in the itemeditor, they can only be either 0 or 1
          "probabilityPlatform2": {"min": 0.0, "max": 1.0, "label": "probabilityPlatform2", "stepsize":0.1},
          "probabilityPlatform3": {"min": 0.0, "max": 1.0, "label": "probabilityPlatform3", "stepsize":0.1},
          "probabilityCoin": {"min": 0.0, "max": 1.0, "label": "probabilityCoin", "stepsize":0.1},
          "probabilityBooster": {"min": 0.0, "max": 1.0, "label": "probabilityBooster", "stepsize":0.1},
          "probabilitySlowDowner": {"min": 0.0, "max": 0.1, "label": "probabilitySlowDowner", "stepsize":0.01}
      }
  }

  // is needed internally to avoid creating too many windows close to each other
  property int lastWindowY: 0

  property int wallHeight: 71

  // the background images are moved up by this offset so on widescreen devices the full background is visible
  property real __yOffsetForWindow: scene.__yOffsetForAbsoluteWindowCoordinates

  property int yCount: 0

  // gets emitted when a BorderRegion.onPlayerCollision() is received
  signal gameLost

  Component.onCompleted: {

    // this creates some platforms, coins and windows beforehand, so they dont need to be created at runtime
    preCreateEntityPool();

    // startGame() is called in SpacyJumpScene.enterScene()
  }

  function preCreateEntityPool() {

    // dont pool entities on Sym & meego - creation takes very long on these platforms
    if(system.isPlatform(System.Meego) || system.isPlatform(System.Symbian))
      return;

    entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/Platform.qml"), 30);
    entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/Coin.qml"), 10);
    entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/Booster.qml"), 10);
    entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/SlowDowner.qml"), 2);
    entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/BorderWall.qml"), 30);
    entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/BorderWallRight.qml"), 30);
  }


  function stopGame() {
      levelMovementAnimation.stop();

      // this function automatically pools all entities which have poolingEnabled set to true
      // and it ignores the entities that have preventFromRemovalFromEntityManager set to true
      entityManager.removeAllEntities();

      player.blockCollisions = 0;

      player.controller.xAxis = 0;
      player.controller.yAxis = 0;
     // player.state = "";
      // only use this for debugging, whena game should immediately be started after it was stopped
      //startGame();

      accelerometer.active = false
  }

  // initialize level data - this function can be called multiple times, so every time a new game gets started
  // it is called from SpacyJumpScene.enterScene()
  function startGame() {
    console.debug("Level: startGame()");

      if(settings.getValue("accelerometerEnabled")) {
          accelerometer.active = true
      }

    levelMovementAnimation.stop();

    // it is important that lastY is set first, so the dy in onYChanged will be 0 and no new row is created
    currentRow = 0;
    lastY = 0;
    level.y = 0;

    player.blockCollisions = 0;
    player.x = scene.width/2;
    player.y = level.y - wallHeight; //2*gridSize;

    player.score = 0;
    player.bonusScore = 0;
    player.bigJumpScore = 0;
    player.bigJump = false;

    player.controller.xAxis = 0;
    player.controller.yAxis = 0;

    // start positioned on the window top
    lastWindowY = 0;

    // create the first two wall segments
//    LevelLogic.createWallSegments(level.y)
    LevelLogic.createWallSegments(level.y - wallHeight)

      // create the platforms on which the player starts
    LevelLogic.createFullBlock(level.y);

      while(level.y < 270) {
         // console.log("level.y:" + level.y)
          level.y += gridSize + 1;
      }

      levelMovementAnimation.start();
      levelMovementAnimation.velocity = -levelMovementSpeedMinimum;

  }

  // handles the repositioning of the background, if they are getting out of the scene
  // internally, 4 images are created below each other so it appears to the user as being one continuous background
  ParallaxScrollingBackground {
    id: levelBackground
    y: -level.y
    sourceImage: "../assets/img/background.png"
    // do not mirror it vertically, because the image is prepared to match on the top and the bottom
    mirrorSecondImage: true
    movementVelocity: Qt.point(0, levelMovementAnimation.velocity)
    running: levelMovementAnimation.running // start non-running, gets set to true in startGame
  }

  // start in the center of the scene, and a little bit below the top
  // the player will fall to the playerInitialBlock below at start
  Player {
    id: player
    x: scene.width/2
    y: gridSize/2
    z: 1

    onShowText: {
        notificationText.text = currentScore;
        notificationText.visible = true;
        bigJumpTextTimer.restart();
    }

    onSlowDownerCollision: {


        if(!slowDownActive){
            if(!speedUpActive) {
                levelOldSpeedSlowDowner = levelMovementAnimation.velocity;
            } else {
                levelOldSpeedSlowDowner = levelOldSpeedSpeedUp;
            }
            slowDownActive = true;
            levelMovementAnimation.velocity = levelMovementSpeedMinimum;
            levelMovementAnimation.acceleration = 0;
            slowDowntimer.restart();
        }
    }
  }



  Timer {
      id: bigJumpTextTimer;
      interval: 1300;
      running: true;
      repeat: false;

      onTriggered: {
        notificationText.visible = false;
      }
  }

  BorderRegion {
    width: scene.gameWindowAnchorItem.width*4
    anchors.horizontalCenter: parent.horizontalCenter
    height: 400

    // the BorderRegion is always out of the visual scene, so it is never visible
    // it moves with the level like the topRegion
    y: -level.y - 400; // -level.y + scene.gameWindowAnchorItem.height  + 100//-height

    variationType: "topRegion"

    onPlayerCollision: {
        // if(!slowDownActive){
        if(!speedUpActive){
            if(!slowDownActive){
                levelOldSpeedSpeedUp = levelMovementAnimation.velocity;
            } else {
                levelOldSpeedSpeedUp = levelOldSpeedSlowDowner;
            }

            levelMovementAnimation.velocity = levelMovementSpeedMaximum * 5;
            speedUpActive = true;
            speedUpTimer.restart();
        }
        console.debug("LEVEL TOP COLLISION");

    }
  }

  Timer {
    id: speedUpTimer;
    interval: 200;
    running: true;
    repeat: false;

    onTriggered: {
        levelMovementAnimation.velocity = levelOldSpeedSpeedUp;
        levelMovementAnimation.acceleration = levelMovementAcceleration;
        speedUpActive = false;
    }
  }

  Timer {
      id: slowDowntimer;
      interval: 2000;
      running: true;
      repeat: false;

      onTriggered: {
          if(!speedUpActive){
              levelMovementAnimation.velocity = levelOldSpeedSlowDowner;
              levelMovementAnimation.acceleration = levelMovementAcceleration;
            }
          slowDownActive = false;
      }
  }

  BorderRegion {
    // make it so big that the player will still loose if he navigates to the right or left of the screen and then falls down
    width: scene.gameWindowAnchorItem.width*4
    anchors.horizontalCenter: parent.horizontalCenter

    height: 20
    // the BorderRegion is always out of the visual scene, so it is never visible
    // it moves with the level like the topRegion
    y: -level.y + scene.gameWindowAnchorItem.height  - 20//-height

    variationType: "bottomRegion"

    onPlayerCollision: {
      console.debug("PLAYER COLLIDED WITH BorderRegion, level.y:", level.y, ", player.y:", player.y)
      // emit the gameLost signal, which is handled in SpacyJumpScene
      gameLost();
    }
  }

  BorderRegion {
      // make it so big that the player will still loose if he navigates to the right or left of the screen and then falls down
      width: scene.gameWindowAnchorItem.width*4
      anchors.horizontalCenter: parent.horizontalCenter

      height: 20
      // the BorderRegion is always out of the visual scene, so it is never visible
      // it moves with the level like the topRegion
      y: -level.y + scene.gameWindowAnchorItem.height  + 100//-height

      variationType: "bottomRegion2"
  }

  MovementAnimation {
    id: levelMovementAnimation
    property: "y"
    // this is the movement in px per second, start with very slow movement, 10 px per second
    velocity: levelMovementSpeedMaximum
    // running is set to false - call start() here
    // increase the velocity by this amount of pixels per second, so it lasts minVelocity/acceleration seconds until the maximum is reached!
    // i.e. -90/-2 = 45 seconds
    acceleration: levelMovementAcceleration;
    target: level
    minVelocity: levelMovementSpeedMinimum
  }

  // when the level gets moved up, check if the difference between last level y position and the current one is greater than gridSize - if so, create a new row
  onYChanged: {
    var dy = y - lastY;

    if(dy > gridSize) {

      var amountNewRows = (dy/gridSize).toFixed();
      console.debug(amountNewRows, "new rows are getting created...")

      for(var i=0; i<amountNewRows; i++) {
          console.debug("level velocity:" + levelMovementAnimation.velocity + ", accel:" + levelMovementAnimation.acceleration)

          LevelLogic.createPlatforms();

          currentRow++;
          lastY += gridSize
      }

        yCount += dy;

      // create wall segments on the side
      if(yCount <= wallHeight){
          LevelLogic.createWallSegments(-level.y - wallHeight);
          yCount = 0;
      }

    }

    // TODO: use a bitmap font for text updating which is much faster -> this feature is not supported by V-Play yet, contact us if you would need it at team@v-play.net
    // for performance reasons, disable the score updating every frame, which is expensive with the text element because a texture is recreated every time the text changes!
    if(enableConstantScoreTextUpdating)
      player.score = level.y.toFixed()
    else
      // divide by an arbitrary number, so the text doesnt get changed every frame which is bad for performance as it is no bitmap font yet!
      player.score = (level.y/40).toFixed()
  }



  // ------------------- for debugging only ------------------- //
  function pauseGame() {
    console.debug("pauseGame()")
    levelMovementAnimation.stop();
  }
  function resumeGame() {
    console.debug("resumeGame()")
    levelMovementAnimation.start();
  }

  function restartGame() {
    console.debug("restartGame()")
    stopGame();
    startGame();
  }
}
